import threading
import time
import MyUtil
import Examiner
import os
import Config
from apscheduler.schedulers.background import BackgroundScheduler
from datetime import datetime

"""
统计者
"""


# 处理日数据分析
# datatime yyyyMMdd
def handle_count_day(datatime):
    # 获取待读取record文件路径、待写入count文件路径
    record_file_path = MyUtil.get_record_bucket_write_path(datatime)
    count_file_path = MyUtil.get_count_bucket_write_path('day', datatime)
    # 检查是否需要进行日统计
    if not Examiner.check_day_count_need(record_file_path, count_file_path):
        MyUtil.loger(f'{datatime}日统计文件已生成'
                     f'且之后{Config.RECORD_FILE_NAME_PREFIX}{datatime}{Config.SYSTEM_STORE_FILE_SUFFIX}文件未修改过，无需再次统计')
        return
    # 读取并统计当天记录文件
    hashset: dict[str, int] = {}
    day_total_count = 0
    with open(record_file_path, 'r') as record_bucket_file:
        for line in record_bucket_file:
            day_total_count += 1
            # 解析记录文件行数据
            parts = line.split(',', 1)
            key = parts[1].split('\n', 1)[0]
            if key in hashset:
                hashset[key] += 1
            else:
                hashset[key] = 1
        # 按值降序排序
        sorted_hashset = sorted(hashset.items(), key=lambda item: item[1], reverse=True)

    # 覆盖记录写入磁盘文件
    os.makedirs(os.path.dirname(count_file_path), exist_ok=True)
    with open(count_file_path, 'w+') as count_bucket_file:
        for key, value in sorted_hashset:
            count_bucket_file.writelines(f'{key} {value}\n')
    # 重命名文件
    file_name_parts = count_file_path.split(datatime)

    os.rename(count_file_path, f'{file_name_parts[0]}{datatime}_{day_total_count}{Config.SYSTEM_STORE_FILE_SUFFIX}')
    MyUtil.loger(f'{datatime}统计完成')
    return


# datatime yyyyMM
def handle_count_month(datatime):
    MyUtil.loger(f'{datatime}月统计任务触发...')
    # 读取对应 record_bucket 存储桶
    record_bucket_path = (f'{Config.RECORD_BUCKET_FILE_HOME_PATH}'
                          f'/{MyUtil.get_date_folder_path(Config.DATE_TYPE_DAY, datatime)}')
    # 检查 record_bucket_path 路径是否存在
    if not Examiner.folder_exists(record_bucket_path):
        MyUtil.loger(f'{record_bucket_path} 文件夹不存在，无法进行月统计')
        return
    # 遍历获取 record_bucket_path 下所有文件
    count_task_set = set()
    for file_name in os.listdir(record_bucket_path):
        # 获取文件名中的日期 yyyyMMdd
        count_task_set.add(file_name
                           .replace('record', '')
                           .split(Config.SYSTEM_STORE_FILE_SUFFIX)[0])

    # 构建 count 作业队列
    thread_num = len(count_task_set) if len(
        count_task_set) < Config.HANDLE_COUNT_MONTH_THREAD_NUM else Config.HANDLE_COUNT_MONTH_THREAD_NUM
    MyUtil.loger(f'开始构建月统计任务\n'
                 f'作业数量：{len(count_task_set)}\n'
                 f'线程数量：{thread_num}\n'
                 f'批次数量：{len(count_task_set) // Config.HANDLE_COUNT_MONTH_THREAD_NUM + 1}')

    for i in range(Config.HANDLE_COUNT_MONTH_THREAD_NUM):
        if len(count_task_set) == 0:
            break
        # 创建线程 执行 count 统计任务，并在作业队列中移除本次入参
        threading.Thread(target=handle_count_day(count_task_set.pop())).start()

    # 归并每日统计结果入月统计结果
    count_day_bucket_path = (f'{Config.COUNT_BUCKET_FILE_HOME_PATH}/{Config.DATE_TYPE_DAY}'
                             f'/{MyUtil.get_date_folder_path(Config.DATE_TYPE_DAY, datatime)}')

    hashset: dict[str, int] = {}
    month_total_count = 0
    for file_name in os.listdir(count_day_bucket_path):
        month_total_count += int((file_name.replace(Config.SYSTEM_STORE_FILE_SUFFIX, '').split('_')[1]))
        # 获取文件名中的日期 yyyyMMdd
        count_date = file_name.replace(Config.COUNT_FILE_NAME_PREFIX, '').split(Config.SYSTEM_STORE_FILE_SUFFIX)[0]
        # 读取并统计当天记录文件
        with open(f'{count_day_bucket_path}/{file_name}', 'r') as count_bucket_file:
            for line in count_bucket_file:
                # 解析记录文件行数据
                parts = line.split(' ', 1)
                key = parts[0]
                value = int(parts[1].split('\n', 1)[0])
                if key in hashset:
                    hashset[key] += value
                else:
                    hashset[key] = value
    # 按值降序排序
    sorted_hashset = sorted(hashset.items(), key=lambda item: item[1], reverse=True)
    # 覆盖记录写入磁盘文件
    count_month_file_path = MyUtil.get_count_bucket_write_path(Config.DATE_TYPE_MONTH, datatime)
    os.makedirs(os.path.dirname(count_month_file_path), exist_ok=True)
    with open(count_month_file_path, 'w+') as count_month_file:
        for key, value in sorted_hashset:
            count_month_file.writelines(f'{key} {value}\n')
    # 重命名文件
    file_name_parts = count_month_file_path.split(datatime)
    os.rename(count_month_file_path,
              f'{file_name_parts[0]}{datatime}_{month_total_count}{Config.SYSTEM_STORE_FILE_SUFFIX}')
    MyUtil.loger(f'{datatime}统计完成')
    return


# datatime yyyy
def handle_count_year(datatime):  # todo
    return


def init():
    """
    定时counter触发器构建
    :return:
    """
    # 创建调度器
    scheduler = BackgroundScheduler()

    # 获取当前时间
    year = datetime.now().year
    month = datetime.now().month
    day = datetime.now().day
    last_month = f'{year}{month - 1}'
    if month - 1 == 0:
        last_month = f'{year - 1}12'

    # 添加定时任务
    # 每天晚上10点执行日统计
    scheduler.add_job(handle_count_day, 'cron', hour=22, minute=0, args=[f'{year}{month}{day}'])
    MyUtil.loger(f'日统计任务调度器注册成功：调度信息为{Config.LOG_SPLIT_CHAR}每天晚上10点执行日统计')
    # 每月1号中午12点执行上月统计
    scheduler.add_job(handle_count_month, 'cron', day=1, hour=12, minute=0, args=[last_month])
    MyUtil.loger(f'月统计任务调度器注册成功：调度信息为{Config.LOG_SPLIT_CHAR}每月1号中午12点执行上月统计')
    # 每年1月1号晚上6点执行上年统计
    scheduler.add_job(handle_count_year, 'cron', month=1, day=1, hour=18, minute=0, args=[year - 1])
    MyUtil.loger(f'年统计任务调度器注册成功：调度信息为{Config.LOG_SPLIT_CHAR}每年1月1号晚上6点执行上年统计')
    MyUtil.loger(f'定时counter触发器构建完成')
    # 启动调度器
    scheduler.start()

    try:
        # 保持主程序运行
        while True:
            time.sleep(2)
    except (KeyboardInterrupt, SystemExit):
        # 关闭调度器
        scheduler.shutdown()
